Jx.declare('Jx.data.tree.Owner', {

	$extend: 'Jx.data.tree.Node',

	$requires: [

		'Jx.lib.Hash'

	],

	$actions: [

		'createNode',

		'registerNode',

		'unregisterNode'

	],

	defaultNodeClass: 'Jx.data.tree.Node',

	requireNodeClass: 'Jx.data.tree.Node',

	rootNode: null,

	nodeName: 'owner',

	ownerType: 'data',

	registeredNodes: undefined,

	constructor: function(){

		this.registeredNodes = Jx.instantiate('Jx.lib.Hash');

		this.initializeRootNode();

		this.$super(arguments);

	},

	initializeRootNode: function(){

		this.rootNode = this.createNode();

	},

	onDestroy: function(){

		this.rootNode.destroy();

		this.$super(arguments);

	},

	onCreateNode: function(operation){

		var node = operation.returnValue = Jx.instantiate(operation.nodeClass, operation.arguments),

			type = this.ownerType;

		//-- create node id
		node.objectId = Jx.id( this.ownerType );

		node.id = node.isSet('id') ?

			node.getAttribute('id')

			:

			node.objectId;

	},

	onAfterCreateNode: function(operation){

		this.registerNode(operation.returnValue);

	},

	onRegisterNode: function(operation, node){

		var oldOwner = node.owner;

		if (oldOwner && oldOwner !== this){

			oldOwner.unregisterNode(node);

		}

		this.registeredNodes.set(node.id, node);

		node.owner = this;

	},

	onAfterRegisterNode: function(operation, node){

		var children = node.childNodes;

		//-- own children
		for(var l = children.length; l--;){

			this.registerNode(children[l]);

		}

		node.on({

			'destroy': this.handleNodeDestroy,

			scope: this

		});

	},

	onUnregisterNode: function(operation, node){

		var parentNode = node.parentNode;

		if (parentNode){

			parentNode.removeChild(node);

		}

		this.registeredNodes.unset(node.id);

		delete node.owner;

	},

	onAfterUnregisterNode: function(operation, node){

		node.un({

			'destroy': this.handleNodeDestroy,

			scope: this

		});

	},

	handleNodeDestroy: function(evt){

		var node = evt.target(),

			parentNode = node.parentNode;

		if (parentNode){

			parentNode.removeChild(node);

		}

		this.unregisterNode(node);

		//-- remove object id
		Jx.id(node.objectId, true);

	},

	allowCreateNode: function(operation, config){

		operation.returnValue = void(0);

		operation.nodeClass = this.defaultNodeClass;

		var attributes = {};

		if (Jx.isObject(config)){

			Jx.assign(attributes, config);

		}

		operation.arguments = [attributes];

	},

	allowRegisterNode: function(operation, node){

		return this.isValidNode(node) && node.owner !== this;

	},

	allowUnregisterNode: function(operation, node){

		return this.isSet(node.id);

	},

	isValidNode: function(node){

		return Jx.instanceOf(node, this.requireNodeClass) && !node.isDestroyed();

	}




});
